package arithm

import (
	"math/big"
	"testing"
)

// TestComplexAddWithInteger tests Complex.ADD method with Integer values
func TestComplexAddWithInteger(t *testing.T) {
	// Test addition with Integer
	x := Complex(3 + 4i)
	y := Integer(5)
	result := x.ADD(y)

	// When adding Complex with Integer, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	expected := Complex(8 + 4i) // (3 + 4i) + 5
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexAddWithBigInteger tests Complex.ADD method with BigInteger values
func TestComplexAddWithBigInteger(t *testing.T) {
	// Test addition with BigInteger
	x := Complex(3 + 4i)
	bigVal, _ := (new(big.Int)).SetString("12345678901234567890", 10)
	y := (*BigInteger)(bigVal)
	result := x.ADD(y)

	// When adding Complex with BigInteger, result should be a Complex
	f, _ := bigVal.Float64()
	expected := Complex(complex(f, 0) + complex(3, 4))
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexAddWithRational tests Complex.ADD method with Rational values
func TestComplexAddWithRational(t *testing.T) {
	// Test addition with Rational
	x := Complex(3 + 4i)
	ratVal := big.NewRat(5, 2) // 2.5
	y := (*Rational)(ratVal)
	result := x.ADD(y)

	// When adding Complex with Rational, result should be a Complex
	f, _ := ratVal.Float64()
	expected := Complex(complex(f, 0) + complex(3, 4))
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexAddWithReal tests Complex.ADD method with Real values
func TestComplexAddWithReal(t *testing.T) {
	// Test addition with Real
	x := Complex(3 + 4i)
	y := Real(2.5)
	result := x.ADD(y)

	// When adding Complex with Real, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	expected := Complex(5.5 + 4i) // (3 + 4i) + 2.5
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexAddWithComplex tests Complex.ADD method with Complex values
func TestComplexAddWithComplex(t *testing.T) {
	// Test addition with Complex
	x := Complex(3 + 4i)
	y := Complex(2 + 3i)
	result := x.ADD(y)

	// When adding Complex with Complex, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	expected := Complex(5 + 7i) // (3 + 4i) + (2 + 3i)
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexSubWithInteger tests Complex.SUB method with Integer values
func TestComplexSubWithInteger(t *testing.T) {
	// Test subtraction with Integer
	x := Complex(3 + 4i)
	y := Integer(5)
	result := x.SUB(y)

	// When subtracting Integer from Complex, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	expected := Complex(-2 + 4i) // (3 + 4i) - 5
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexSubWithBigInteger tests Complex.SUB method with BigInteger values
func TestComplexSubWithBigInteger(t *testing.T) {
	// Test subtraction with BigInteger
	x := Complex(3 + 4i)
	bigVal, _ := (new(big.Int)).SetString("12345678901234567890", 10)
	y := (*BigInteger)(bigVal)
	result := x.SUB(y)

	// When subtracting BigInteger from Complex, result should be a Complex
	f, _ := bigVal.Float64()
	expected := Complex(complex(3, 4) - complex(f, 0))
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexSubWithRational tests Complex.SUB method with Rational values
func TestComplexSubWithRational(t *testing.T) {
	// Test subtraction with Rational
	x := Complex(3 + 4i)
	ratVal := big.NewRat(5, 2) // 2.5
	y := (*Rational)(ratVal)
	result := x.SUB(y)

	// When subtracting Rational from Complex, result should be a Complex
	f, _ := ratVal.Float64()
	expected := Complex(complex(3, 4) - complex(f, 0))
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexSubWithReal tests Complex.SUB method with Real values
func TestComplexSubWithReal(t *testing.T) {
	// Test subtraction with Real
	x := Complex(3 + 4i)
	y := Real(2.5)
	result := x.SUB(y)

	// When subtracting Real from Complex, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	expected := Complex(0.5 + 4i) // (3 + 4i) - 2.5
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexSubWithComplex tests Complex.SUB method with Complex values
func TestComplexSubWithComplex(t *testing.T) {
	// Test subtraction with Complex
	x := Complex(3 + 4i)
	y := Complex(2 + 3i)
	result := x.SUB(y)

	// When subtracting Complex from Complex, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	expected := Complex(1 + 1i) // (3 + 4i) - (2 + 3i)
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexMulWithInteger tests Complex.MUL method with Integer values
func TestComplexMulWithInteger(t *testing.T) {
	// Test multiplication with Integer
	x := Complex(3 + 4i)
	y := Integer(5)
	result := x.MUL(y)

	// When multiplying Complex with Integer, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	expected := Complex(15 + 20i) // (3 + 4i) * 5
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexMulWithBigInteger tests Complex.MUL method with BigInteger values
func TestComplexMulWithBigInteger(t *testing.T) {
	// Test multiplication with BigInteger
	x := Complex(3 + 4i)
	bigVal, _ := (new(big.Int)).SetString("12345678901234567890", 10)
	y := (*BigInteger)(bigVal)
	result := x.MUL(y)

	// When multiplying Complex with BigInteger, result should be a Complex
	f, _ := bigVal.Float64()
	expected := Complex(complex(3, 4) * complex(f, 0))
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexMulWithRational tests Complex.MUL method with Rational values
func TestComplexMulWithRational(t *testing.T) {
	// Test multiplication with Rational
	x := Complex(3 + 4i)
	ratVal := big.NewRat(5, 2) // 2.5
	y := (*Rational)(ratVal)
	result := x.MUL(y)

	// When multiplying Complex with Rational, result should be a Complex
	f, _ := ratVal.Float64()
	expected := Complex(complex(3, 4) * complex(f, 0))
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexMulWithReal tests Complex.MUL method with Real values
func TestComplexMulWithReal(t *testing.T) {
	// Test multiplication with Real
	x := Complex(3 + 4i)
	y := Real(2.5)
	result := x.MUL(y)

	// When multiplying Complex with Real, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	expected := Complex(7.5 + 10i) // (3 + 4i) * 2.5
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexMulWithComplex tests Complex.MUL method with Complex values
func TestComplexMulWithComplex(t *testing.T) {
	// Test multiplication with Complex
	x := Complex(3 + 4i)
	y := Complex(2 + 3i)
	result := x.MUL(y)

	// When multiplying Complex with Complex, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	expected := Complex(-6 + 17i) // (3 + 4i) * (2 + 3i) = (3*2 - 4*3) + (3*3 + 4*2)i = -6 + 17i
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexDivWithInteger tests Complex.DIV method with Integer values
func TestComplexDivWithInteger(t *testing.T) {
	// Test division with Integer
	x := Complex(6 + 8i)
	y := Integer(2)
	result := x.DIV(y)

	// When dividing Complex by Integer, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	expected := Complex(3 + 4i) // (6 + 8i) / 2
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexDivWithBigInteger tests Complex.DIV method with BigInteger values
func TestComplexDivWithBigInteger(t *testing.T) {
	// Test division with BigInteger
	x := Complex(6 + 8i)
	bigVal, _ := (new(big.Int)).SetString("12345678901234567890", 10)
	y := (*BigInteger)(bigVal)
	result := x.DIV(y)

	// When dividing Complex by BigInteger, result should be a Complex
	f, _ := bigVal.Float64()
	expected := Complex(complex(6, 8) / complex(f, 0))
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexDivWithRational tests Complex.DIV method with Rational values
func TestComplexDivWithRational(t *testing.T) {
	// Test division with Rational
	x := Complex(6 + 8i)
	ratVal := big.NewRat(5, 2) // 2.5
	y := (*Rational)(ratVal)
	result := x.DIV(y)

	// When dividing Complex by Rational, result should be a Complex
	f, _ := ratVal.Float64()
	expected := Complex(complex(6, 8) / complex(f, 0))
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexDivWithReal tests Complex.DIV method with Real values
func TestComplexDivWithReal(t *testing.T) {
	// Test division with Real
	x := Complex(6 + 8i)
	y := Real(2.5)
	result := x.DIV(y)

	// When dividing Complex by Real, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	expected := Complex(2.4 + 3.2i) // (6 + 8i) / 2.5
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestComplexDivWithComplex tests Complex.DIV method with Complex values
func TestComplexDivWithComplex(t *testing.T) {
	// Test division with Complex
	x := Complex(6 + 8i)
	y := Complex(2 + 3i)
	result := x.DIV(y)

	// When dividing Complex by Complex, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	// (6 + 8i) / (2 + 3i) = ((6 + 8i) * (2 - 3i)) / ((2 + 3i) * (2 - 3i))
	// = (12 - 18i + 16i + 24) / (4 + 9) = (36 - 2i) / 13 = 36/13 - (2/13)i
	// Expected result: approximately 2.769230769230769 - 0.15384615384615385i
	// Let's check if the real and imaginary parts are close enough
	resultComplex := complex128(result.(Complex))
	expectedReal := 36.0 / 13.0
	expectedImag := -2.0 / 13.0
	
	// Allow for small floating point differences
	tolerance := 1e-15
	realDiff := float64(real(resultComplex)) - expectedReal
	imagDiff := float64(imag(resultComplex)) - expectedImag
	
	if realDiff > tolerance || realDiff < -tolerance {
		t.Errorf("Expected real part %v, got %v", expectedReal, real(resultComplex))
	}
	
	if imagDiff > tolerance || imagDiff < -tolerance {
		t.Errorf("Expected imaginary part %v, got %v", expectedImag, imag(resultComplex))
	}
}
